﻿using hentity;
using hlog;
using hutil;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace hq {
    public abstract class ZtTask:ITask {

        public TaskStat getStat() {
            return stat;
        }

        public TaskStat stat = new TaskStat();
        protected String className;

        private Task jobTask;
        protected int time = 600;
        protected bool exceptionSleep = true;
        protected int oneTimeSleep = 0;
        private int extralSleep = 5000;
        public bool runed = false;
        public ZtTask() {
            className = this.GetType().Name;
            stat.className = className;
        }
        protected virtual bool init() {
            return true;
        }
        public void start() {
            try {
                if( runed ) {
                    console("已经启动");
                }
                if( !init() ) {
                    console("初始化异常");
                    return;
                }
                runed = false;
                jobTask = Task.Factory.StartNew(() => { doAction(); } ,TaskCreationOptions.LongRunning);
                consoleOnly("成功");
            } catch( Exception e ) {
                LoggerCommon.error(className + "初始化异常，请查看日志记录" ,e);
            }
        }
        protected virtual bool onlyOneTimeAsync() {
            return true;
        }
        protected virtual long oneMaxTime() {
            return 2000 + time + oneTimeSleep;
        }
        private void doAction() {
            do {
                try {
                    work();
                    Thread.Sleep(time + oneTimeSleep);
                    oneTimeSleep = 0;
                    extralSleep = 3000;
                } catch( Exception ex ) {
                    stat.exceptionCount++;
                    String show = string.Format("{0} sleep {1}s :{2}" ,className ,extralSleep / 1000 ,ex.Message);
                    LoggerCommon.error(show ,ex);
                    exceptionSleeps();
                }
            } while( true );
        }
        /// <summary>
        ///
        /// </summary>
        public void work() {
            lock( stat ) {
                if( !runed ) {
                    runed = onlyOneTimeAsync();
                    stat.time = this.time;
                }

                ITask t = TaskPool.getIniting();
                long beginTime = DateTime.Now.Ticks;
                if( t == null ) {
                    excute();
                } else {
                    consoleOnly(t.GetType().Name + "初始化中");
                }
                afterExcute();
                analysis(beginTime);
            }
        }
        public virtual void afterExcute() { } 
        void analysis(long beginTime)
        {
            var n = DateTime.Now;
            long lastTime = (n.Ticks - beginTime) / 10000;
            long d = beginTime - HUtil.randSeek;
            d = d > 0 ? d >> 40 : 0;
            stat.worklastTime = lastTime;
            if (lastTime > oneMaxTime())
            {
                fileAll("线程执行时间过长" + lastTime);
            }
            stat.workAllTime += lastTime;
            stat.workCount++;
            if (lastTime > stat.maxTime)
            {
                stat.maxTime = lastTime;
            }
            if (lastTime < stat.minTime || stat.minTime == 0)
            {
                stat.minTime = lastTime;
            }
            oneTimeSleep = oneTimeSleep==0?(int)d: oneTimeSleep;

        }
        private void exceptionSleeps()
        {
            Thread.Sleep(extralSleep);
            extralSleep *= 2;
            if (extralSleep > 120000)
            {
                extralSleep = 120000;
            }
        }
        abstract public void excute();
        public void fileAll(String format, params object[] p)
        {
            if (p.Length > 0)
            {
                format = String.Format(format, p);
            }
            LoggerCommon.fileAll(className + "->" + format);
        }
        public void console(String format, params object[] p)
        {
            if (p.Length > 0)
            {
                format = String.Format(format, p);
            }
            LoggerCommon.consol(className + "->" + format);
        }
        public void consoleOnly(String format, params object[] p)
        {
            if (p.Length > 0)
            {
                format = String.Format(format, p);
            }
            LoggerCommon.consoleOnly(className + "->" + format);
        }

        public bool isRuned() {
            return runed;
        }
    }
}
